package net.jiastudy.web.config;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.annotation.Order;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.builders.WebSecurity;
import org.springframework.security.config.annotation.web.builders.WebSecurity.IgnoredRequestConfigurer;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.config.annotation.web.configurers.ExpressionUrlAuthorizationConfigurer;
import org.springframework.security.config.http.SessionCreationPolicy;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.web.AuthenticationEntryPoint;
import org.springframework.security.web.access.AccessDeniedHandler;
import org.springframework.security.web.authentication.AuthenticationFailureHandler;
import org.springframework.security.web.authentication.AuthenticationSuccessHandler;
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;
import org.springframework.security.web.util.matcher.AntPathRequestMatcher;

import net.jiastudy.web.authentication.AuthenticationFilter;
import net.jiastudy.web.authentication.JWTAuthenticationFilter;
import net.jiastudy.web.authentication.JsonAccessDeniedHandler;
import net.jiastudy.web.authentication.JsonAuthenticationEntryPoint;
import net.jiastudy.web.authentication.JsonAuthenticationHandler;
import net.jiastudy.web.authentication.JwtAuthenticationSuccessHandler;

@EnableWebSecurity
public class MultiHttpSecurityConfig {

	@Autowired
	protected UserDetailsService userDetailService;

	@Autowired
	private PasswordEncoder passwordEncoder;

	@Autowired
	public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception {
		auth.userDetailsService(userDetailService).passwordEncoder(passwordEncoder);
	}

	@Configuration
	@Order(1)
	public static class JwtWebSecurityConfig extends WebSecurityConfigurerAdapter {
		
		@Autowired
		private IgnoredUrlsProperties ignoredUrlsProperties;
		
		@Bean
		protected AccessDeniedHandler getJsonAccessDeniedHandler() {
			return new JsonAccessDeniedHandler();
		}
		
		@Bean
		protected AuthenticationSuccessHandler getJwtAuthenticationSuccessHandler() {
			return new JwtAuthenticationSuccessHandler();
		}
		
		@Bean
		protected AuthenticationFailureHandler getJsonAuthenticationFailureHandler() {
			return new JsonAuthenticationHandler();
		}
		
		@Bean
		protected AuthenticationEntryPoint getJsonAuthenticationEntryPoint() {
			return new JsonAuthenticationEntryPoint();
		}
		
		@Override
		protected void configure(HttpSecurity http) throws Exception {
			ExpressionUrlAuthorizationConfigurer<HttpSecurity>.ExpressionInterceptUrlRegistry registry = http
					.authorizeRequests();
			registry.and()
					// 表单登录方式
					.formLogin().loginPage("/login/jwt").permitAll()
					// 成功处理类
					.successHandler(this.getJwtAuthenticationSuccessHandler())
					// 失败
					.failureHandler(this.getJsonAuthenticationFailureHandler()).and().logout().permitAll().and().authorizeRequests()
					// 任何请求
					.anyRequest()
					// 需要身份认证
					.authenticated().and()
					// 关闭跨站请求防护
					.csrf().disable()
					// 前后端分离采用JWT 不需要session
					.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS).and()
					.exceptionHandling().authenticationEntryPoint(this.getJsonAuthenticationEntryPoint()).and()
					// 自定义权限拒绝处理类
					.exceptionHandling().accessDeniedHandler(this.getJsonAccessDeniedHandler()).and()
					// 添加JWT过滤器 除/login其它请求都需经过此过滤器
					.addFilter(new JWTAuthenticationFilter(authenticationManager(), getApplicationContext()))
					.addFilterAt(authenticationFilter(), UsernamePasswordAuthenticationFilter.class);
		}
		
		@Bean
	    public AuthenticationFilter authenticationFilter() throws Exception {
			AuthenticationFilter authenticationFilter
	            = new AuthenticationFilter();
	        authenticationFilter.setAuthenticationSuccessHandler(getJwtAuthenticationSuccessHandler());
	        authenticationFilter.setAuthenticationFailureHandler(getJsonAuthenticationFailureHandler());
	        authenticationFilter.setRequiresAuthenticationRequestMatcher(new AntPathRequestMatcher("/login/jwt", "POST"));
	        authenticationFilter.setAuthenticationManager(authenticationManagerBean());
	        return authenticationFilter;
	    }
		
		@Override
	    public void configure(WebSecurity web) throws Exception {
			IgnoredRequestConfigurer ignoredRequestConfigurer = web.ignoring();
			for(String url:ignoredUrlsProperties.getUrls()){
				ignoredRequestConfigurer.antMatchers(url);
	        }
	    }
	}
}
